#include "index_reader.h"

int IndexReader::Init(const char* indexPath)
{
    char file[NAME_LEN];
    for(int i = 0; i < LEVEL_NUM; ++i)
    {
        snprintf(file, sizeof(file), "%s/%s.%d.0", indexPath, INDEX0_NAME, i);
        FILE* fp = fopen(file, "r");
        if(fp == NULL) 
        {
            FATAL("index loader : fopen %s error, failed", file);
            return E_RET; 
        }
        fseek(fp, 0, SEEK_END);
        uint64_t flen = ftell(fp);
        rewind(fp);
        assert(flen % sizeof(idx_index0_t) == 0);
        uint32_t num = flen / sizeof(idx_index0_t);
        m_num[i] = num;
        if(num > 0)
        {
            m_index0[i] = new(std::nothrow) idx_index0_t[num];
            if(NULL == m_index0[i])
            {
                FATAL("index malloc m_index0[%d] failed", i);
                return E_RET;
            }
            size_t ret = fread(m_index0[i], sizeof(idx_index0_t), num, fp);
            if(ret != num)
            {
                FATAL("read index file[%s] is error", file);
                return E_RET;
            }
        }
        fclose(fp);
    }
    IniContext iniContext;
    snprintf(file, sizeof(file), "%s/%s", indexPath, INDEX_INFO_NAME);
    if(iniLoadFromFile(file, &iniContext) != 0) 
    {
        FATAL("error load file:%s", file);
        return E_RET;
    }
    char tstr[NAME_LEN];
    for(int i = 0; i < LEVEL_NUM; ++i)
    {
        if(m_num[i] <= 0)
            continue;
        snprintf(tstr, sizeof(tstr), "%s_%d_num", INDEX1_NAME, i);
        uint32_t num = iniGetIntValue(NULL, tstr, &iniContext, -1);
        m_index1_file[i] = new(std::nothrow) IndexFile[num];
        if(NULL == m_index1_file[i])
        {
            FATAL("index malloc m_index1_file[%d] failed", i);
            return E_RET;
        }
        for(uint32_t j = 0; j < num; ++j)
        {
            snprintf(file, sizeof(file), "%s/%s.%d.%d", indexPath, INDEX1_NAME, i, j);
            int fd = open(file, O_RDONLY, 0666);
            if(fd < 0)
            {
                FATAL("open file[%s] is error", file);
                return E_RET;
            }
            m_index1_file[i][j].fd = fd;
            uint64_t flen = lseek(fd, 0, SEEK_END);
            assert(flen % sizeof(idx_index1_t) == 0);
            if(flen < 0)
            {
                FATAL("lseek file[%s] is error", file);
                return E_RET;
            }
            void* ptr = mmap(NULL, flen, PROT_READ, MAP_SHARED, fd, 0);

            if( ptr == MAP_FAILED)
            {
                FATAL("mmap file[%s] is fail!", file);
                return E_RET;
            }
            m_index1_file[i][j].mmapPtr = ptr;
            m_index1_file[i][j].size = flen;
        }
        snprintf(tstr, sizeof(tstr), "%s_%d_num", IDX_FNAME, i);
        num = iniGetIntValue(NULL, tstr, &iniContext, -1);
        m_index2_file[i] = new(std::nothrow) IndexFile[num];
        if(NULL == m_index2_file[i])
        {
            FATAL("index malloc m_index2_file[%d] failed", i);
            return E_RET;
        }
        for(uint32_t j = 0; j < num; ++j)
        {
            snprintf(file, sizeof(file), "%s/%s.%d.%d", indexPath, IDX_FNAME, i, j);
            int fd = open(file, O_RDONLY, 0666);
            if(fd < 0)
            {
                FATAL("open file[%s] is error", file);
                return E_RET;
            }
            m_index2_file[i][j].fd = fd;
            uint64_t flen = lseek(fd, 0, SEEK_END);
            if(flen < 0)
            {
                FATAL("lseek file[%s] is error", file);
                return E_RET;
            }
            void* ptr = mmap(NULL, flen, PROT_READ, MAP_SHARED, fd, 0);

            if( ptr == MAP_FAILED)
            {
                FATAL("mmap file[%s] is fail!", file);
                return E_RET;
            }
            m_index2_file[i][j].mmapPtr = ptr;
            m_index2_file[i][j].size = flen;
        }

    }
    return S_RET;
}

int IndexReader::ReadIndex(uint64_t termSign, IndexList* indexList, int level)
{
    if(m_num[level] == 0)
    {
        indexList->idxHead = NULL;
        indexList->idxIndex = NULL;
        indexList->idxCount = NULL;
        indexList->offSet = NULL;
        return E_RET;
    }
    int32_t low = 0;
    int32_t high = m_num[level]-1;
    int32_t mid = 0;
    idx_index0_t* index0 = m_index0[level];
    int32_t index1_no = -1;
    while(low <= high)
    {
        mid = (low + high) / 2;
        if(index0[mid].tsign_l > termSign)
            high = mid - 1;
        else if(index0[mid].tsign_h < termSign)
            low = mid + 1;
        else
        {
            index1_no = mid;
            break;
        }
    }
    if(index1_no == -1)
    { 
        indexList->idxHead = NULL;
        indexList->idxIndex = NULL;
        indexList->idxCount = NULL;
        indexList->offSet = NULL;
        return E_RET;
    }
    DEBUG("0 id[%d], low[%llu], high[%llu]", index1_no, index0[index1_no].tsign_l, index0[index1_no].tsign_h);
    int fd = m_index1_file[level][index0[index1_no].fno_index1].fd;
    int num = NUM_LINKS_PER_INDEX0_BLOCK;
    if(index1_no == m_num[level]-1)
    {
        num = (m_index1_file[level][0].size/sizeof(idx_index1_t))%NUM_LINKS_PER_INDEX0_BLOCK;
    }
    if (readahead(fd, index0[index1_no].foff_in_index1, sizeof(idx_index1_t)*num)!= 0)
    {
        WARNING("readahead index1 level[%d] fno[%d] is fail!", level, index0[index1_no].fno_index1);
    }
    idx_index1_t* index1 = (idx_index1_t*)m_index1_file[level][index0[index1_no].fno_index1].mmapPtr;
    low = 0;
    high = num-1;
    int32_t index2_no = -1;
    while(low <= high)
    {
        mid = (low+high) / 2;
        if(index1[mid].tsign > termSign)
            high = mid - 1;
        else if(index1[mid].tsign < termSign)
            low = mid + 1;
        else 
        {
            index2_no = mid;
            break;
        }
    }
    if(index2_no == -1)
    {
        indexList->idxHead = NULL;
        indexList->idxIndex = NULL;
        indexList->idxCount = NULL;
        indexList->offSet = NULL;
        return E_RET;
    }
    NOTICE("1 fno[%d], sign[%llu], off[%u]", index1[index2_no].fno, index1[index2_no].tsign, index1[index2_no].foff);
    fd = m_index2_file[level][index1[index2_no].fno].fd;
    if (readahead(fd, index1[index2_no].foff, sizeof(idx_head_t)) != 0)
    {
        WARNING("readahead index2 level[%d] fno[%d] is fail!", level, index1[index2_no].fno);
    }
    char* ptr = (char*)m_index2_file[level][index1[index2_no].fno].mmapPtr + index1[index2_no].foff;
    indexList->idxHead = (idx_head_t*)(ptr);
    DEBUG("2 num_idx[%u], num_off[%u], sign[%llu]", indexList->idxHead->num_idx, indexList->idxHead->num_off, indexList->idxHead->tsign);
    uint32_t indexSize = indexList->idxHead->num_idx*(sizeof(idx_index_t)+sizeof(idx_count_t)) \
                         + indexList->idxHead->num_off*sizeof(offset_t);
    if (readahead(fd, index1[index2_no].foff+sizeof(idx_head_t), indexSize) != 0)
    {
        WARNING("readahead index2 level[%d] fno[%d] is fail!", level, index1[index2_no].fno);
    }
    indexList->idxIndex = (idx_index_t*)((char*)ptr+sizeof(idx_head_t));
    indexList->idxCount = (idx_count_t*)((char*)ptr+sizeof(idx_head_t)+sizeof(idx_index_t)*indexList->idxHead->num_idx);
    indexList->offSet = (offset_t*)((char*)ptr+sizeof(idx_head_t)+indexList->idxHead->num_idx*(sizeof(idx_index_t)+sizeof(idx_count_t)));
    return S_RET;
}

int IndexReader::ReadIndex(char* termStr, IndexList* indexList, int level)
{
    uint64_t termSign = 0;
    if(create_sign64(termStr, strlen(termStr), &termSign) < 0)
    {   
        FATAL("create_sign64 is error, term[%s]", termStr);
        return -1; 
    }   
    return ReadIndex(termSign, indexList, level);
}




















/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
